/*
 * @(#)XfdmFlatSystem.java        1.0 2000/05/09
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

package xfuzzy.xfdm.model.algorithm;

import xfuzzy.lang.*;
import xfuzzy.xfdm.model.*;

/**
 * Algoritmo que genera un grid con comportamiento plano
 * 
 * @author Francisco Jos� Moreno Velo
 *
 */
public class XfdmFlatSystem extends XfdmAlgorithm {

	//----------------------------------------------------------------------------//
	//                                CONSTRUCTOR                                 //
	//----------------------------------------------------------------------------//

	/**
	 * Constructor
	 */
	public XfdmFlatSystem(){
	}

	//----------------------------------------------------------------------------//
	//                             M�TODOS P�BLICOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Obtiene el nombre del algoritmo
	 */
	public String toString() {
		return "Flat System";
	}

	/**
	 * Representaci�n en el fichero de configuraci�n
	 */
	public String toXML() {
		return "\t\t<algorithm name=\"Flat\"></algorithm>";
	}

	/**
	 * Obtiene el tipo de base de conocimiento que genera el algoritmo
	 */
	public int getKnowledgeBaseKind() {
		return KnowledgeBase.RULE_SET;
	}

	/**
	 * Indica si el algoritmo necesita que las variables de entrada tengan creadas
	 * las funciones de pertenencia. En caso contrario el algoritmo debe encargarse
	 * de dar contenido a los tipos de las variables de entrada.
	 */
	public boolean needInputMemFuncs() {
		return true;
	}
	
	/**
	 * Indica si el algoritmo necesita que las variables de salida tengan creadas
	 * las funciones de pertenencia. En caso contrario el algoritmo debe encargarse
	 * de dar contenido a los tipos de las variables de salida.
	 */
	public boolean needOutputMemFuncs() {
		return true;
	}

	/**
	 * Indica si el algoritmo necesita que la estructura del sistema est� creada.
	 * Este requisito es propio de los algoritmo que contienen alguna etapa de
	 * optimizaci�n param�trica.
	 * @return
	 */
	public boolean needSystemStructure() {
		return false;
	}
	
	/**
	 * Indica si el algoritmo es v�lido para problemas de clasificaci�n
	 * @return
	 */
	public boolean supportsClassification() {
		return false;
	}
	
	/**
	 * Indica si el algoritmo es v�lido para problemas de regresi�n
	 * @return
	 */
	public boolean supportsRegression() {
		return true;
	}

	/**
	 * Genera el contenido de la base de conocimiento a partir de los datos
	 */
	public void extractKnowlegde(KnowledgeBase base, XfdmConfig config ) {
		Variable ivar[] = base.getInputs();
		Variable ovar[] = base.getOutputs();
		int numinputs = ivar.length;
		int numoutputs = ovar.length;
		int numrules = computeGridSize(ivar);

		int is = Relation.IS;
		int index[] = new int[numinputs];
		LinguisticLabel pmf[][] = new LinguisticLabel[numinputs][];
		for(int i=0; i<numinputs; i++) {
			pmf[i] = ivar[i].getType().getAllMembershipFunctions();
		}

		LinguisticLabel omf[][] = new LinguisticLabel[numoutputs][];
		for(int i=0; i<numoutputs; i++) {
			omf[i] = ovar[i].getType().getAllMembershipFunctions();
		}

		boolean classif = (config.getSystemStyle().getDefuzMethod() == XfdmSystemStyle.CLASSIFICATION);
		for(int i=0; i<numrules; i++) {
			Relation rel = Relation.create(is,null,null,ivar[0],pmf[0][index[0]],base);
			for(int j=1; j<numinputs; j++) {
				Relation nrel = Relation.create(is,null,null,ivar[j],pmf[j][index[j]],base);
				rel = Relation.create(Relation.AND,rel,nrel,null,null,base);
			}
			Rule rule = new Rule(rel);
			for(int j=0; j<numoutputs; j++) {
				if(classif) {
					rule.add(new Conclusion(ovar[j],omf[j][0],base));
				} else {
					rule.add(new Conclusion(ovar[j],omf[j][i],base));
				}
			}
			((RuleSet) base).addRule(rule);

			for(int j=numinputs-1; j>=0; j--) {
				index[j]++;
				if(index[j] == pmf[j].length) index[j] = 0;
				else break;
			}
		}
	}

	/**
	 * Calcula el n�mero de reglas del grid 
	 */
	private int computeGridSize(Variable[] ivar) {
		int number=1;
		for(int i=0; i<ivar.length; i++) {
			number *= ivar[i].getType().getAllMembershipFunctions().length;
		}
		return number;
	}

}


